namespace SharpTalk.Core
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using Base;
    using Data;
    using Diagnostic;
    using Enums;
    using Extensions;
    using Exceptions;

    /// <summary>
    /// 
    /// </summary>
    public sealed class ChatRoomManager : ChatRoomManagerBase
    {
        /// <summary>
        /// Creates a new instance of the <see cref="T:SharpTalk.Core.ChatRoomManager"/> class.
        /// </summary>
        public ChatRoomManager(IChatRoomDataProvider dataProvider, ITraceProvider trace)
            : base(dataProvider)
        {
            TraceProvider = trace;
        }
        /// <summary>
        /// Creates a new instance of the <see cref="T:SharpTalk.Core.ChatRoomManager"/> class.
        /// </summary>
        public ChatRoomManager(IChatRoomDataProvider dataProvider)
            : base(dataProvider)
        {
        }
        /// <summary>
        /// Creates a new <see cref="T:SharpTalk.Core.ChatRoom"/>
        /// </summary>
        /// <param name="name">The name of the <see cref="T:SharpTalk.Core.ChatRoom"/></param>
        /// <param name="type">The <see cref="T:SharpTalk.Core.Enums.ChatRoomTypeEnum"/> of the <see cref="T:SharpTalk.Core.ChatRoom"/></param>
        /// <param name="passwordhash">The password hash of the <see cref="T:SharpTalk.Core.ChatRoom"/></param>
        /// <param name="owner"></param>
        /// <returns>A new instance of the <see cref="T:SharpTalk.Core.ChatRoom"/> class or null.</returns>
        public override ChatRoom Create(string name, ChatRoomTypeEnum type, byte[] passwordhash, string motd, Guid owner)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            if (String.IsNullOrEmpty(name) ||
               (type.HasFlag(ChatRoomTypeEnum.Protected) && passwordhash == null) ||
               owner == Guid.Empty) return null;

            if(DataProvider.Find(name)!=null)
                throw new ChatRoomNameException(Resources.Messages.chatroom_name_already_exists);

            var chatroom = new ChatRoom(Guid.NewGuid())
                               {
                                   Name = name,
                                   Type = type,
                                   PasswordHash = passwordhash,
                                   Owner = owner,
                                   Motd = motd
                               };

            return  DataProvider.Save(chatroom) ? chatroom : null;
        }
        /// <summary>
        /// Finds a <see cref="T:SharpTalk.Core.ChatRoom"/>.
        /// </summary>
        /// <param name="name">The name of the <see cref="T:SharpTalk.Core.ChatRoom"/></param>
        /// <returns>An instance of the <see cref="T:SharpTalk.Core.ChatRoom"/> class or null.</returns>
        public override ChatRoom Find(string name)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            return DataProvider.Find(name);
        }
        /// <summary>
        /// Finds a <see cref="T:SharpTalk.Core.ChatRoom"/>.
        /// </summary>
        /// <param name="name">The name of the <see cref="T:SharpTalk.Core.ChatRoom"/></param>
        /// <param name="type">The <see cref="T:SharpTalk.Core.Enums.ChatRoomTypeEnum"/> of the <see cref="T:SharpTalk.Core.ChatRoom"/></param>
        /// <returns>An instance of the <see cref="T:SharpTalk.Core.ChatRoom"/> class or null.</returns>
        public override ChatRoom Find(string name, ChatRoomTypeEnum type)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            return DataProvider.Find(name, type);
        }
        /// <summary>
        /// Finds a list of <see cref="T:SharpTalk.Core.ChatRoom"/>.
        /// </summary>
        /// <param name="type">The <see cref="T:SharpTalk.Core.Enums.ChatRoomTypeEnum"/> of the <see cref="T:SharpTalk.Core.ChatRoom"/></param>
        /// <returns>A list of <see cref="T:SharpTalk.Core.ChatRoom"/>.</returns>
        public override List<ChatRoom> Find(ChatRoomTypeEnum type)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            return DataProvider.Find(type);
        }
        /// <summary>
        /// Finds a <see cref="T:SharpTalk.Core.ChatRoom"/>.
        /// </summary>
        /// <param name="guid">The <see cref="T:System.Guid"/> of the <see cref="T:SharpTalk.Core.ChatRoom"/></param>
        /// <returns>A <see cref="T:SharpTalk.Core.ChatRoom"/> or null.</returns>
        public override ChatRoom Find(Guid guid)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            return DataProvider.Find(guid);
        }
        /// <summary>
        /// Deletes a <see cref="T:SharpTalk.Core.ChatRoom"/>.
        /// </summary>
        /// <param name="chatroom">The <see cref="T:SharpTalk.Core.ChatRoom"/> to delete.</param>
        /// <returns>True if success otherwise False</returns>
        public override bool Delete(ChatRoom chatroom)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            return DataProvider.Delete(chatroom);
        }
        /// <summary>
        /// Deletes a <see cref="T:SharpTalk.Core.ChatRoom"/>
        /// </summary>
        /// <param name="guid">The <see cref="T:System.Guid"/> of the <see cref="T:SharpTalk.Core.ChatRoom"/></param>
        /// <returns>True if succes otherwise False</returns>
        public override bool Delete(Guid guid)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            return DataProvider.Delete(guid);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Save(ChatRoom obj)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            return DataProvider.Save(obj);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override List<ChatRoom> All()
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            return DataProvider.All();
        }
        /// <summary>
        /// Update a <see cref="T:SharpTalk.Core.ChatRoom"/>
        /// </summary>
        /// <param name="chatRoom">An instance of the <see cref="T:SharpTalk.Core.ChatRoom"/> class.</param>
        public override ChatRoom Update(ChatRoom chatRoom)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            return Update(chatRoom, true);
        }

        /// <summary>
        /// Update a <see cref="T:SharpTalk.Core.ChatRoom"/>
        /// </summary>
        /// <param name="chatRoom">An instance of the <see cref="T:SharpTalk.Core.ChatRoom"/> class.</param>
        /// <param name="definePassword"></param>
        public override ChatRoom Update(ChatRoom chatRoom, bool definePassword)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            DataProvider.Update(chatRoom, definePassword);
            return DataProvider.Find(chatRoom.Guid);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="chatroomGuid"></param>
        /// <param name="user"></param>
        /// <param name="password"></param>
        public override ChatRoomDetails Join(Guid chatroomGuid, Guid user, byte[] password)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            var room = DataProvider.Find(chatroomGuid);
            if (room == null)
                throw new ChatRoomException(Resources.Messages.chatroom_not_found);

            if( room.Type.HasFlag(ChatRoomTypeEnum.Protected) &&
                !room.PasswordHash.Equals<byte>(password))
                throw new ChatRoomException(Resources.Messages.chatroom_invalid_password);

            return DataProvider.Join(chatroomGuid, user)
                ? new ChatRoomDetails(room){ Owner =  room.Owner == user ? room.Owner : Guid.Empty }
                : null;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="chatroomGuid"></param>
        /// <param name="user"></param>
        public override bool Leave(Guid chatroomGuid, Guid user)
        {
            TraceMethodCall(MethodBase.GetCurrentMethod());
            DataProvider.Leave(chatroomGuid,user);
            return true;
        }
    }
}